﻿using DG.Tweening;
using TMPro;
using UnityEngine;

/// <summary>
/// 血量显示条，支持当前血量、护盾、防御和最大血量显示，并带护盾出现和消失动画。
/// 文字颜色动态变化，护盾为0时文字颜色与背景色一致，护盾显示蓝色。
/// </summary>
[RequireComponent(typeof(Transform))]
public class HealthTextBar : MonoBehaviour
{
    // ========= 逻辑层数据部分 =========
    private int _currentHealth;
    private int _defense;
    private int _maxHealth;
    private (int current, int defense, int max)? _pendingHealthData; // 缓存动画期间最新数据

    // 动画状态标记，避免重复触发动画
    private bool _isShieldClearing = false;
    private bool _isShieldAppearing = false;

    /// <summary>
    /// 外部调用接口，设置当前血量、护盾和最大血量，自动触发显示更新和动画。
    /// </summary>
    public void SetHealth(int current, int defense, int max)
    {
        int newMax = Mathf.Max(1, max);
        int newCurrent = Mathf.Clamp(current, 0, newMax);
        int newDefense = Mathf.Max(0, defense);

        // 动画进行中时，缓存数据，等待动画完成后处理
        if (_isShieldClearing || _isShieldAppearing)
        {
            _pendingHealthData = (newCurrent, newDefense, newMax);
            return;
        }

        // 护盾由有变无，执行护盾消失动画
        if (_defense > 0 && newDefense == 0)
        {
            AnimateShieldClear(newCurrent, newMax, shieldClearDuration, () =>
            {
                ApplyHealthData(newCurrent, newDefense, newMax);
            });
        }
        // 护盾由无变有，先更新血量显示无护盾状态，再执行护盾出现动画
        else if (_defense == 0 && newDefense > 0)
        {
            _currentHealth = newCurrent;
            _defense = 0;
            _maxHealth = newMax;
            UpdateDisplay();

            AnimateShieldAppear(newDefense, newCurrent, newMax, shieldAppearDuration, () =>
            {
                _defense = newDefense;
                UpdateDisplay();
                ProcessPendingData();
            });
        }
        // 普通更新
        else
        {
            if (_currentHealth != newCurrent || _defense != newDefense || _maxHealth != newMax)
            {
                ApplyHealthData(newCurrent, newDefense, newMax);
            }
        }
    }

    /// <summary>
    /// 应用数据并刷新显示，完成后处理缓存数据。
    /// </summary>
    private void ApplyHealthData(int current, int defense, int max)
    {
        _currentHealth = current;
        _defense = defense;
        _maxHealth = max;
        UpdateDisplay();
        ProcessPendingData();
    }

    /// <summary>
    /// 检查是否有缓存的更新数据，有则继续调用 SetHealth。
    /// </summary>
    private void ProcessPendingData()
    {
        if (_pendingHealthData.HasValue)
        {
            var data = _pendingHealthData.Value;
            _pendingHealthData = null;
            SetHealth(data.current, data.defense, data.max);
        }
    }

    /// <summary>
    /// 护盾出现动画，蓝条淡入并横向放大至目标比例。
    /// </summary>
    private void AnimateShieldAppear(int newDefense, int newCurrent, int newMax, float duration, TweenCallback onComplete)
    {
        if (_isShieldAppearing) return;
        _isShieldAppearing = true;

        blueTotalBar.enabled = true;
        blueTotalBar.DOKill();
        blueTotalBar.color = new Color(_blueTotalColor.r, _blueTotalColor.g, _blueTotalColor.b, 0f);
        blueTotalBar.transform.DOKill();

        float targetBlueRatio = GetBlueRatio(newCurrent, newDefense, newMax);

        blueTotalBar.transform.localScale = new Vector3(0f, _initialLocalScale.y, _initialLocalScale.z);

        Sequence seq = DOTween.Sequence();
        seq.Append(blueTotalBar.DOColor(_blueTotalColor, duration * 0.5f).SetEase(animationEase));
        seq.Join(blueTotalBar.transform.DOScaleX(targetBlueRatio, duration).SetEase(animationEase));
        seq.OnComplete(() =>
        {
            _isShieldAppearing = false;
            onComplete?.Invoke();
        });
    }

    /// <summary>
    /// 护盾消失动画，先调整绿条到正确比例，再渐隐蓝条和绿条。
    /// </summary>
    private void AnimateShieldClear(int newCurrent, int newMax, float duration, TweenCallback onComplete)
    {
        if (_isShieldClearing) return;
        _isShieldClearing = true;

        float targetGreenRatio = GetGreenRatio(newCurrent, 0, newMax);

        greenHealthBar.DOKill();
        blueTotalBar.DOKill();

        Tween greenScaleTween = greenHealthBar.transform.DOScaleX(targetGreenRatio, 0.3f).SetEase(animationEase);

        Sequence seq = DOTween.Sequence();
        seq.Append(greenScaleTween);
        seq.AppendInterval(0f);
        seq.Append(blueTotalBar.DOColor(new Color(_blueTotalColor.r, _blueTotalColor.g, _blueTotalColor.b, 0f), duration - 0.3f).SetEase(animationEase));
        seq.Join(greenHealthBar.DOColor(GetGreenColor(), duration - 0.3f).SetEase(animationEase));
        seq.OnComplete(() =>
        {
            blueTotalBar.enabled = false;
            blueTotalBar.color = _blueTotalColor;
            _isShieldClearing = false;
            onComplete?.Invoke();
        });
    }

    // ========= 逻辑计算函数 =========

    /// <summary>计算蓝条比例（护盾+当前血量占最大血量比例，超过1时取1）</summary>
    private float GetBlueRatio(int current, int defense, int max)
    {
        if (current + defense >= max)
            return 1f;
        return (float)(current + defense) / max;
    }

    /// <summary>计算绿条比例（当前血量占最大血量或当前血量占血+护盾总和）</summary>
    private float GetGreenRatio(int current, int defense, int max)
    {
        if (current + defense >= max)
            return (float)current / (current + defense);
        return (float)current / max;
    }

    /// <summary>获取当前绿条颜色，低血量时显示警告色</summary>
    private Color GetGreenColor()
    {
        float healthRatio = (float)_currentHealth / _maxHealth;
        return healthRatio < _lowHealthThreshold ? _lowHealthColor : _greenHealthColor;
    }

    /// <summary>判断是否显示蓝条</summary>
    private bool ShowBlueBar() => _defense > 0 || (_currentHealth + _defense) > _maxHealth;

    // ========= UI视图层部分 =========

    [Header("文本显示设置")]
    [SerializeField] private TMP_Text hpText;
    [SerializeField] private string currentHealthHex = "#FFFFFF";
    [SerializeField] private string defenseHex = "#808080";
    [SerializeField] private string maxHealthHex = "#FFFFFF";

    [Header("血条层级元素（从内到外）")]
    [SerializeField] private SpriteRenderer whiteBackground;
    [SerializeField] private SpriteRenderer blueTotalBar;
    [SerializeField] private SpriteRenderer greenHealthBar;

    [Header("基础动画设置")]
    [SerializeField] private float animationDuration = 0.25f;
    [SerializeField] private Ease animationEase = Ease.InOutSine;

    [Header("护盾动画设置")]
    [SerializeField] private float shieldAppearDuration = 0.3f;
    [SerializeField] private float shieldClearDuration = 0.7f;

    [Header("颜色设置")]
    [SerializeField] private Color _whiteColor = Color.white;
    [SerializeField] private Color _blueTotalColor = new Color(0.5f, 0.7f, 1f, 1f);
    [SerializeField] private Color _greenHealthColor = Color.green;
    [SerializeField] private Color _lowHealthColor = Color.red;
    [Range(0f, 1f)]
    [SerializeField] private float _lowHealthThreshold = 0.2f;

    private Vector3 _initialLocalScale;
    private string HealthFormat => $"<color={currentHealthHex}>{{0}}</color> / <color={defenseHex}>{{1}}</color> / <color={maxHealthHex}>{{2}}</color>";

    private void Awake()
    {
        if (!ValidateComponents())
        {
            enabled = false;
            return;
        }

        SetupHierarchy();

        _initialLocalScale = whiteBackground.transform.localScale;

        blueTotalBar.transform.localPosition = Vector3.zero;
        greenHealthBar.transform.localPosition = Vector3.zero;

        blueTotalBar.transform.localScale = _initialLocalScale;
        greenHealthBar.transform.localScale = _initialLocalScale;

        whiteBackground.color = _whiteColor;
        blueTotalBar.color = _blueTotalColor;
        greenHealthBar.color = _greenHealthColor;

        whiteBackground.sortingOrder = 0;
        blueTotalBar.sortingOrder = 1;
        greenHealthBar.sortingOrder = 2;

        blueTotalBar.enabled = false;
    }

    /// <summary>
    /// 确保蓝条和绿条为白色背景的子对象，保持层级关系正确
    /// </summary>
    private void SetupHierarchy()
    {
        if (blueTotalBar.transform.parent != whiteBackground.transform)
        {
            Vector3 ws = blueTotalBar.transform.lossyScale;
            blueTotalBar.transform.SetParent(whiteBackground.transform);
            blueTotalBar.transform.localScale = ws;
        }
        if (greenHealthBar.transform.parent != whiteBackground.transform)
        {
            Vector3 ws = greenHealthBar.transform.lossyScale;
            greenHealthBar.transform.SetParent(whiteBackground.transform);
            greenHealthBar.transform.localScale = ws;
        }
    }

    /// <summary>
    /// 验证所有组件是否已赋值，缺失则报错并禁用脚本
    /// </summary>
    private bool ValidateComponents()
    {
        bool ok = true;
        if (whiteBackground == null)
        {
            Debug.LogError("白色背景未赋值", this);
            ok = false;
        }
        if (blueTotalBar == null)
        {
            Debug.LogError("蓝色总条未赋值", this);
            ok = false;
        }
        if (greenHealthBar == null)
        {
            Debug.LogError("绿色现血条未赋值", this);
            ok = false;
        }
        return ok;
    }

    /// <summary>
    /// 统一更新血条和文字显示，含动画和颜色调整
    /// </summary>
    private void UpdateDisplay()
    {
        UpdateText();

        bool showBlueBar = ShowBlueBar();
        blueTotalBar.enabled = showBlueBar;

        float blueRatio = GetBlueRatio(_currentHealth, _defense, _maxHealth);
        float greenRatio = GetGreenRatio(_currentHealth, _defense, _maxHealth);
        Color greenColor = GetGreenColor();

        // 限制精度，减少浮点误差
        blueRatio = Mathf.Round(blueRatio * 1000f) / 1000f;
        greenRatio = Mathf.Round(greenRatio * 1000f) / 1000f;

        // 取消当前动画，避免冲突
        greenHealthBar.DOKill();
        blueTotalBar.DOKill();
        greenHealthBar.transform.DOKill();
        blueTotalBar.transform.DOKill();

        // 绿条颜色和缩放动画
        greenHealthBar.DOColor(greenColor, animationDuration);
        greenHealthBar.transform.DOScaleX(greenRatio, animationDuration)
            .SetEase(animationEase)
            .SetUpdate(true);

        // 蓝条缩放动画
        blueTotalBar.transform.DOScaleX(blueRatio, animationDuration)
            .SetEase(animationEase)
            .SetUpdate(true);

        // 强制对齐防止位置抖动
        blueTotalBar.transform.localPosition = Vector3.zero;
        greenHealthBar.transform.localPosition = Vector3.zero;
    }

    /// <summary>
    /// 更新文本显示，血量和护盾颜色动态变化，护盾为0时与背景颜色一致。
    /// </summary>
    private void UpdateText()
    {
        if (hpText == null) return;

        // 当前血量颜色动态，低血量红色提醒
        Color currentHpColor = GetGreenColor();
        string currentHpHex = ColorUtility.ToHtmlStringRGB(currentHpColor);

        // 护盾颜色，护盾为0显示为背景白色，护盾存在显示蓝色
        Color defenseColor = (_defense == 0) ? _whiteColor : _blueTotalColor;
        string defenseHex = ColorUtility.ToHtmlStringRGB(defenseColor);

        // 最大血量颜色固定为白色
        string maxHpHex = ColorUtility.ToHtmlStringRGB(_whiteColor);

        hpText.text = $"<color=#{currentHpHex}>{_currentHealth}</color> / <color=#{defenseHex}>{_defense}</color> / <color=#{maxHpHex}>{_maxHealth}</color>";
    }

    /// <summary>
    /// LateUpdate 保证条形图的位置始终正确，避免抖动
    /// </summary>
    private void LateUpdate()
    {
        if (blueTotalBar != null) blueTotalBar.transform.localPosition = Vector3.zero;
        if (greenHealthBar != null) greenHealthBar.transform.localPosition = Vector3.zero;
    }

    /// <summary>
    /// 脚本销毁时，停止所有DOTween动画，防止内存泄漏
    /// </summary>
    private void OnDestroy()
    {
        if (greenHealthBar != null) greenHealthBar.DOKill();
        if (blueTotalBar != null) blueTotalBar.DOKill();
        if (hpText != null) hpText.DOKill();
        DOTween.Kill(this);
    }
}
